'' VGA_1024.spin
'' MODIFED BY JEFF LEDGER / AKA OLDBITCOLLECTOR

{{
Info            : VT100 Terminal for AVR CP/M
Autor           : Joe G.
Version         : 00
Subversion      : 02
Funktion        : Keyboard Driver DE, VGA-1024x768 Driver, V24 Driver, VT100 Terminal
Komponenten     : vga_Hires_Text

Log             

10.04.2013      Start, CR, LF
}}


CON
  cols     = 80 '128                ' number of screen columns
  rows     = 40 '64                 ' number of screen rows
  chars    = rows*cols          ' number of screen characters
  esc      = $CB                ' keyboard esc char

OBJ
 vga : "vga_Hires_Text"

VAR
  byte  screen[chars]           ' screen character buffer
  word  colors[rows]            ' color specs for each screen row (see ColorPtr description above)
  byte  cursor[6]               ' cursor info array (see CursorPtr description above)
  long  sync, loc, xloc, yloc   ' sync used by VGA routine, others are local screen pointers
  long  kbdreq                  ' global val of kbdflag

PUB start(BasePin) | i, char


''start vga
  vga.start(BasePin, @screen, @colors, @cursor, @sync)
  waitcnt(clkfreq * 1 + cnt)    'wait 1 second for cogs to start

''init screen colors to gold on blue
  repeat i from 0 to rows - 1
    colors[i] := $08F0          '$2804 (if you want cyan on blue)

''init cursor attributes
  cursor[2] := %110             ' init cursor to underscore with slow blink

  cls                           ' clear screen

PUB bin(value, digits)

'' Print a binary number, specify number of digits

  repeat while digits > 32
    out("0")
    digits--

  value <<= 32 - digits

  repeat digits
    out((value <-= 1) & 1 + "0")

PUB binFP(value) | bitnum, bit, bitval
'' Prints FP long in special Binary format: sign, exp, mantissa

  repeat bitnum from 31 to 0
    bit := 1 << bitnum                ' create mask bit
    bitval := (bit & value) >> bitnum  ' extract bit and shift back to bit 0

    bin(bitval, 1)                    ' display one bit

    case bitnum
      27,20,16,12,8,4: out($20)       ' space after every 4 in group
      31,23: str(string("  "))        ' two after sign and exponent

PUB cls

'' clear screen

  longfill(@screen, $20202020, chars/4)

  xloc := cursor[0] := 0 'right & left
  yloc := cursor[1] := 1 'from top
  loc  := xloc + yloc*cols


PUB home

  xloc := cursor[0] := 0 'right & left
  yloc := cursor[1] := 1 'from top
  loc  := xloc + yloc*cols

PUB color(ColorVal) | i
''reset screen colors
  repeat i from 0 to rows - 1
    colors[i] := $0000 + ColorVal

PUB rowcolor(ColorVal, row)
'' reset row color to colorval
  if row > rows-1
    row := rows-1

   colors[row] := $0000 + ColorVal


PUB cursloc(x, y)

'' move cursor to x, y position

  xloc := cursor[0] := x
  yloc := cursor[1] := y
  loc  := xloc + yloc*cols

PUB dec(value) | i

'' Print a decimal number

  if value < 0
    -value
    out("-")

  i := 1_000_000_000

  repeat 10
    if value => i
      out(value/i + "0")
      value //= i
      result~~
    elseif result or i == 1
      out("0")
    i /= 10



PUB hex(value, digits)

'' Print a hexadecimal number, specify number of digits

  repeat while digits > 8
    out("0")
    digits--

  value <<= (8 - digits) << 2

  repeat digits
    out(lookupz((value <-= 4) & $f : "0".."9", "A".."F"))

PRI newline | i, j, len
  if ++yloc == rows                           ' if last line on screen, shift all up
    yloc--                                    ' reset yloc it at bottom of screen
    i := @screen
    i += cols
    len := (chars - cols)/4
    longmove(@screen, i, len)                 ' shift screen up one line

    i := @screen
    i += (chars - cols)                       ' set "i" for use below

  else                                        ' if not last line, shift lines down
    i := @screen
    i += (rows - 2)*cols                      ' init ptr to start of next-to-last line

    'if yloc < rows - 1
    '  repeat j from rows - 2 to yloc
    '   longmove(i + cols, i, cols/4)           ' shift one line down
    '   i -= cols                               ' move i up one line

    i += cols                                 ' point to start of last line moved

  longfill(i, $20202020, cols/4)              ' clear the last line moved

  j := i - cols + xloc                        ' point to original cursor location
  bytemove(i, j, cols - xloc)                 ' move chars from cursor pos down to start of next line

  bytefill(j, $20, cols - xloc)               ' clear original part of line that was moved

  xloc := cursor[0] := 0                      ' reset xloc, loc and cursor position
  cursor[1] := yloc
  loc  := yloc*cols

PUB out(c) | i, j, temp
'' Print a character
''
''  $09 = tab
''  $0D = return -> CR/LF
''  $20..$7E = display character
''  $7F = skip
''  $C0   left arrow
''  $C1 = right arrow
''  $C2 = up arrow
''  $C3 = down arrow
''  $C4 = home key - go to beginning of line
''  $C5 = end key - go past last char on line
''  $C6 = page up key - skip this key
''  $C7 = page down key - skip this key
''  $C8 = backspace key
''  $C9 = delete key
''  $CA = insert key - skip this key
''  $CB = esc - skip this key

  case c
    $09:                        ' tab command
      repeat
        out($20)                ' recursive call to out( )
      while xloc & 3            ' tab to multiples of 4

    $0A:                        'LF, return to start of new line
      temp := cursor[0]         'save column cursor position
      newline                   'newline
      cursor[0] := xloc := temp 'restore column cursor position
      loc := xloc + yloc*cols   'output position

    $0D:                        'CR, home key - move to 1st char of line
      xloc := cursor[0] := 0
      loc := xloc + yloc*cols


    $20..$FF:                   ' character                     //7E
      screen[loc++] := c        ' output the character

      if ++xloc == cols         ' bump the xloc
        xloc := 0
        yloc++
        if yloc == rows
          yloc := loc := 0

      if loc == chars           ' wrap if needed
        loc := xloc := yloc := cursor[0] := cursor[1] := 0
      else
        cursor[0] := xloc
        cursor[1] := yloc


    $C0:                        ' left arrow
      if loc                    ' skip this if at upper left screen
        loc--
        if xloc
          xloc--
        else
          xloc := cols - 1
          yloc--
        cursor[0] := xloc
        cursor[1] := yloc

    $C1:                        ' right arrow
      if loc <> chars - 1       ' skip if at lower right of screen
        loc++
        if xloc <> cols - 1
          xloc++
        else
          xloc := 0
          yloc++
        cursor[0] := xloc
        cursor[1] := yloc

    $C2:                        ' up arrow
      if yloc                   ' skip if yloc at top of screen
        yloc--                  ' move yloc up one row
        loc -= cols             ' move loc var back one row
        cursor[1] := yloc       ' reset 'y' cursor position

    $C3:                        ' down arrow
      if yloc <> rows - 1       ' skip if at bottom of screen
        yloc++                  ' move yloc dowm one row
        loc += cols             ' move loc var down one row
        cursor[1] := yloc

    $C4:                        ' home key - move to 1st char of line
      xloc := cursor[0] := 0
      loc := xloc + yloc*cols

    $C5:                        ' end key - move to last char of line
      if xloc <> cols - 1
        repeat xloc from cols - 1 to 0
         loc := xloc + yloc*cols
         if screen[loc] <> $20  ' continue until first non-space char
           if xloc <> cols - 1
             xloc++               ' move past non-blank char
             loc++
           quit

        cursor[0] := xloc       ' loc is already reset from above

    $C8:                        ' backspace
      if loc                    ' skip if at upper left of screen
        if xloc                 ' do 'else' if at start of line
          xloc--                ' xloc left one space
          loc--

          i := @screen          ' calculate
          i += xloc + yloc*cols ' destination for shift left one
          bytemove(i, i+1, cols - xloc - 1)
          screen[cols - 1 + yloc*cols] := $20

        else                    ' here if xloc == 0
          if screen[loc-1] == $20   ' last char on prev line
            yloc--

            i := @screen          ' calculate
            i += loc - 1          ' destination for shift left one

            repeat while screen[--loc] == $20
              bytemove(i, i+1, cols) ' move one row's worth of chars
              i--                 ' dec "i" to correspond to --loc

              screen[loc + cols] := $20  ' clear old char

              if ++xloc == cols   ' use xloc as counter here, 0..., don't move > 1 row
                loc--             ' make as if loc had been bumped above B4 we quit
                quit

            loc++                 ' bump loc to space char
            xloc := loc - yloc*cols ' re-calculate xloc from loc and yloc

        cursor[0] := xloc         ' reset cursor loc
        cursor[1] := yloc

    $C9:                          ' delete
      if xloc == cols - 1
        screen[loc] := $20        ' if at last char on line, clear it and exit

      else
        repeat i from xloc to cols - 2
          j := i + yloc*cols
          screen[j] := screen[j+1]

       screen[j+1] := $20       ' clear last char on line after shift left

PUB str(string_ptr)

'' Print a zero terminated string

  repeat strsize(string_ptr)
    out(byte[string_ptr++])